package io.renren.modules.app.controller;

import com.alibaba.fastjson.JSONObject;
import io.renren.common.utils.R;
import io.renren.modules.app.config.WxPayConfig;
import io.renren.modules.app.entity.OrderEntity;
import io.renren.modules.app.entity.WxOrderPay;
import io.renren.modules.app.service.OrderService;
import io.renren.modules.app.service.WxOrderPayService;
import io.renren.modules.app.weixin_pay.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.weixin4j.WeixinException;
import org.weixin4j.WeixinSupport;
import org.weixin4j.http.HttpsClient;
import org.weixin4j.http.Response;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;


@RequestMapping("/app")
@RestController
public class WeixinController extends WeixinSupport {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    WxPayConfig wxPayConfig;

    @RequestMapping("/wxlogin/MP_verify_LUL2O7taa37OpHVZ.txt")
    public String runGetCode(){
        return "LUL2O7taa37OpHVZ";
    }
    @Autowired
    WxOrderPayService wxOrderPayService;

    @Autowired
    private OrderService orderService;


    /**
     * 用户同意授权，获取code
     * @return openid
     * @throws WeixinException
     * @throws IOException
     */
    @RequestMapping("/wxcode")
    public void getCode(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        Map<String, Object> ret = new HashMap<String, Object>();
        //拼接参数
        String param = "?appid=" + wxPayConfig.getAppid()+
                "&redirect_uri=" +URLEncoder.encode(wxPayConfig.getREDIRECT_URI()) +
                "&response_type=code&scope=snsapi_base#wechat_redirect " ;
        //创建请求对象
//        HttpsClient http = new HttpsClient();
        System.out.println("https://open.weixin.qq.com/connect/oauth2/authorize"+param);
        resp.sendRedirect("https://open.weixin.qq.com/connect/oauth2/authorize"+param);
//        Response res = http.get("https://open.weixin.qq.com/connect/oauth2/authorize"+param);

    }
    /**
     * 向微信平台发送获取access_token请求，并返回openId
     *
     * @param code    登陆时得到的code
     * @param request
     * @return openid
     * @throws WeixinException
     * @throws IOException
     */
    @RequestMapping(value = "/wxlogin", method = RequestMethod.GET)
    public Map<String, Object> login( @RequestParam String code,
                                      HttpServletRequest request,
                                      HttpServletResponse response) throws WeixinException, IOException {
        OAuthJsToken oAuthInfo = null;
        if (code == null || code.equals("")) {
            throw new WeixinException("invalid null, code is null.");
        }

        Map<String, Object> ret = new HashMap<String, Object>();
        //拼接参数
        String param =  "?appid=" + wxPayConfig.getAppid() + "&secret=" + wxPayConfig.getSecret()
                        + "&code=" + code+"&grant_type=" + wxPayConfig.getGrant_type() ;


        //创建请求对象
        HttpsClient http = new HttpsClient();
        //调用获取access_token接口
        Response res = http.get("https://api.weixin.qq.com/sns/oauth2/access_token" + param);
        System.out.println("https://api.weixin.qq.com/sns/oauth2/access_token" + param);
        //根据请求结果判定，是否验证成功
        JSONObject jsonObj = res.asJSONObject();
        if (jsonObj != null) {
            Object errcode = jsonObj.get("errcode");
            if (errcode != null) {
                //返回异常信息
                throw new WeixinException(getCause(Integer.parseInt(errcode.toString())));
            }
            oAuthInfo = new OAuthJsToken();
            oAuthInfo.setAccess_token(jsonObj.getString("access_token"));
            oAuthInfo.setExpires_in(jsonObj.getString("expires_in"));
            oAuthInfo.setRefresh_token(jsonObj.getString("refresh_token"));
            oAuthInfo.setOpenid(jsonObj.getString("openid"));
            oAuthInfo.setScope(jsonObj.getString("scope"));
//            ObjectMapper mapper = new ObjectMapper();
//            OAuthJsToken oauthJsToken = mapper.readValue(jsonObj.toJSONString(), OAuthJsToken.class);
//            System.out.println("44444");
//            logger.info("openid=" + oauthJsToken.getOpenid());
//            ret.put("openid", oauthJsToken.getOpenid());
            ret .put("oAuthInfo",oAuthInfo);

        }
        return ret;
    }

    /**
     * 发起微信支付
     *
     * @param
     * @param request
     * @return
     */
    @RequestMapping(value ="/wxPay", method = RequestMethod.GET)
    public R wxPay(@RequestParam("orderId") String orderId, @RequestParam("openId") String openId, HttpServletRequest request) {
//        OrderEntity orderEntity = new OrderEntity();
        OrderEntity orderEntity = orderService.getOneByOrderId(orderId);
        System.out.println("---------"+orderId);
        try {
            //生成的随机字符串
            String nonce_str = StringUtils.getRandomStringByLength(32);

            //商品名称
            String body =orderEntity.getOrderSubject();
//            String body="xxlxlxl";
            String orderNo = orderEntity.getOrderId();
            Double dou=orderEntity.getOrderMoney()*100;

            String orderMoney=dou.intValue()+"";//支付金额，单位：分，这边需要转成字符串类型，否则后面的签名会失败
//            System.out.println("==========="+orderMoney);
//            String orderMoney= "101";
            //获取本机的ip地址
            String spbill_create_ip = IpUtils.getIpAddr(request);

            Map<String, String> packageParams = new HashMap<String, String>();
            packageParams.put("appid", wxPayConfig.getAppid());
            packageParams.put("mch_id", wxPayConfig.getMch_id());
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("body", body);
            packageParams.put("out_trade_no", orderNo);//商户订单号
            packageParams.put("total_fee", orderMoney);//支付金额，这边需要转成字符串类型，否则后面的签名会失败
            packageParams.put("spbill_create_ip", spbill_create_ip);
            packageParams.put("notify_url", wxPayConfig.getNotify_url());
            packageParams.put("trade_type", wxPayConfig.getTRADETYPE());
            packageParams.put("openid", openId);

            // 除去数组中的空值和签名参数
            packageParams = PayUtil.paraFilter(packageParams);
            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串

            //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, wxPayConfig.getKey(), "utf-8").toUpperCase();
            logger.info("=======================第一次签名：" + mysign + "=====================");
            //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
            String xml = "<xml>" + "<appid>" + wxPayConfig.getAppid() + "</appid>"
                    + "<body><![CDATA[" + body + "]]></body>"
                    + "<mch_id>" + wxPayConfig.getMch_id() + "</mch_id>"
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<notify_url>" + wxPayConfig.getNotify_url() + "</notify_url>"
                    + "<openid>" + openId + "</openid>"
                    + "<out_trade_no>" + orderNo + "</out_trade_no>"
                    + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"
                    + "<total_fee>" + orderMoney + "</total_fee>"
                    + "<trade_type>" + wxPayConfig.getTRADETYPE() + "</trade_type>"
                    + "<sign>" + mysign + "</sign>"
                    + "</xml>";
            System.out.println("调试模式_统一下单接口 请求XML数据：" + xml);

            //调用统一下单接口，并接受返回的结果
            String result = PayUtil.httpRequest(wxPayConfig.getPay_url(), "POST", xml);

            System.out.println("调试模式_统一下单接口 返回XML数据：" + result);

            // 将解析结果存储在HashMap中
            Map map = PayUtil.doXMLParse(result);

            String return_code = (String) map.get("return_code");//返回状态码
            System.out.println("=--------------"+return_code);
            //返回给移动端需要的参数
            Map<String, Object> response = new HashMap<String, Object>();
            if (return_code == "SUCCESS" || return_code.equals(return_code)) {
                // 业务结果
                String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
                response.put("nonceStr", nonce_str);
                response.put("package", "prepay_id=" + prepay_id);
                Long timeStamp = System.currentTimeMillis() / 1000;
                response.put("timeStamp", timeStamp+ "");//这边要将返回的时间戳转化成字符串，不然服务端调用wx.requestPayment方法会报签名错误

                String stringSignTemp = "appId=" + wxPayConfig.getAppid() + "&nonceStr=" + nonce_str
                                        + "&package=prepay_id=" + prepay_id + "&signType=" + wxPayConfig.getSIGNTYPE()
                                        + "&timeStamp=" + timeStamp;
                //再次签名，这个签名用于服务端调用wx.requesetPayment方法
                String paySign = PayUtil.sign(stringSignTemp, wxPayConfig.getKey(), "utf-8").toUpperCase();
                logger.info("=======================第二次签名：" + paySign + "=====================");
                response.put("paySign", paySign);

                //更新订单信息
                //业务逻辑代码
                WxOrderPay wxOrderPay=new WxOrderPay();
                wxOrderPay.setOrderid(orderNo);
                wxOrderPay.setOpenid(openId);
                wxOrderPay.setAmount(orderMoney);
                wxOrderPay.setAppid(openId);
                wxOrderPay.setAliapy(orderMoney);
                wxOrderPay.setFailure("1");
                wxOrderPayService.insetrByWxOrderPay(wxOrderPay);
            }
            response.put("appid", wxPayConfig.getAppid());

            return R.ok().put("data",response);
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("发起失败");
        }

    }

    /**
     * 微信服务器通知支付结果API
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/wxNotify")
    public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        //sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
        System.out.println("接收到的报文：" + notityXml);

        Map map = PayUtil.doXMLParse(notityXml);


        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确
            if (PayUtil.verify(PayUtil.createLinkString(map), (String) map.get("sign"), wxPayConfig.getKey()
                    , "utf-8")) {
                /**此处添加自己的业务逻辑代码start**/


                /**此处添加自己的业务逻辑代码end**/

                //通知微信服务器已经支付成功
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }

        System.out.println(resXml);
        System.out.println("微信支付回调数据结束");

        //商户处理后同步返回给微信信息，参考：https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8
        BufferedOutputStream out = new BufferedOutputStream(
                response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }
    @RequestMapping("/pay/refund")
    @ResponseBody
    public  String wechatRefund(@RequestParam ("orderId") String orderId,HttpServletResponse response, HttpServletRequest request) throws UnsupportedEncodingException {

        String currTime = myUtils.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom =myUtils. buildRandom(4) + "";
        String nonce_str = strTime + strRandom;
        String nonce = StringUtils.getRandomStringByLength(32);
        String out_refund_no = nonce;
        WxOrderPay wxOrderPay =  wxOrderPayService.selectByWxOrderPay(orderId);
        System.out.println(wxOrderPay.getOrderid());
        String total_fee = wxOrderPay.getAmount();
        String refund_fee =   wxOrderPay.getAliapy();
        String out_trade_no=wxOrderPay.getOrderid();
//        String out_trade_no = "123";
//        String total_fee = "101";
//        String refund_fee = "101";
        SortedMap<String, String> parameters = new TreeMap<String, String>();
        parameters.put("appid", wxPayConfig.getAppid());
        parameters.put("mch_id", wxPayConfig.getMch_id());
        parameters.put("nonce_str", nonce_str);
        // 在notify_url中解析微信返回的信息获取到 transaction_id，此项不是必填，详细请看上图文档
        // parameters.put("transaction_id", "微信支付订单中调用统一接口后微信返回的 transaction_id");
        parameters.put("out_trade_no", out_trade_no);
        parameters.put("out_refund_no", out_refund_no); //我们自己设定的退款申请号，约束为UK
        parameters.put("total_fee", total_fee); //单位为分
        parameters.put("refund_fee", refund_fee); //单位为分
        // 操作员帐号, 默认为商户号
        parameters.put("op_user_id", wxPayConfig.getMch_id());
        RequestHandler requestHandler = new RequestHandler(request, response);
        requestHandler.init(wxPayConfig.getAppid(), wxPayConfig.getSecret(), wxPayConfig.getKey());
        String sign = requestHandler.createSign(parameters);

        String createOrderURL = "https://api.mch.weixin.qq.com/sandboxnew/secapi/pay/refund";
        System.out.println("=======================第一次签名：" + sign + "=====================");
        String xml = "<xml>"
                + "<appid><![CDATA[" + wxPayConfig.getAppid() + "]]></appid>"
                + "<mch_id><![CDATA[" + wxPayConfig.getMch_id() +"]]></mch_id>"
                + "<nonce_str><![CDATA[" + nonce_str + "]]></nonce_str>"
                + "<out_trade_no><![CDATA[" + out_trade_no + "]]></out_trade_no>"
                + "<out_refund_no><![CDATA[" + out_refund_no + "]]></out_refund_no>"
                + "<total_fee><![CDATA[" + total_fee + "]]></total_fee>"
                + "<refund_fee><![CDATA[" + refund_fee + "]]></refund_fee>"
                + "<op_user_id><![CDATA[" + wxPayConfig.getMch_id() + "]]></op_user_id>"
                + "<sign>" + sign + "</sign>"
                + "</xml>";
        System.out.println("调试模式_统一退款接口 请求XML数据：" + xml);
        WxOrderPay wxOrder=new WxOrderPay();
        try {
            Map map = myUtils.forRefund(createOrderURL, xml);
            System.out.println("-----------"+map);
            if(map != null){
                wxOrder.setPeopleid(out_trade_no);
                wxOrder.setRefund(refund_fee);
                String return_code = (String) map.get("return_code");
                String result_code = (String) map.get("result_code");
                if(return_code.equals("SUCCESS") && result_code.equals("SUCCESS")){
                    wxOrder.setRefundyesandour("2");
                    wxOrderPayService.updateByWxOrderPay(wxOrder,orderId);
                    System.out.println("退款成功");
                } else {
                    wxOrder.setRefundyesandour("2");
                    wxOrderPayService.updateByWxOrderPay(wxOrder,orderId);
                    System.out.println("退款失败");
                }
            } else {
                wxOrder.setRefundyesandour("2");
                wxOrderPayService.updateByWxOrderPay(wxOrder,orderId);
                System.out.println("退款失败");
            }
        } catch (Exception e) {
            wxOrder.setRefundyesandour("2");
            wxOrderPayService.updateByWxOrderPay(wxOrder,orderId);
            System.out.print("退款失败");
            e.printStackTrace();
        }
        return null;
    }

}